package com.example.demo.com.java8.stream;

import com.example.demo.com.java8.lambda.Apple;
import org.junit.Test;

import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import static java.util.Comparator.comparing;

/**
 * 中间操作
 *
 * @author chengfei5
 * @date 2018/8/21
 */
public class TestStream2 {
    private List<Apple> appleList = Arrays.asList(
            new Apple(155, "green"),
            new Apple(155, "red"),
            new Apple(120, "green"),
            new Apple(159, "green"),
            new Apple(160, "red"),
            new Apple(110, "yellow"),
            new Apple(170, "red"),
            new Apple(180, "green")
    );

    /**
     * filter :过滤操作
     */
    @Test
    public void test1() {
        //中间操作：不会执行任何操作
        Stream<Apple> stream = appleList.stream()
                .filter(apple -> {
                    //内部迭代
                    System.out.println("中间操作不会执行");
                    return apple.getWeight() > 150;
                });
        //只有执行终止操作才会一次执行，也叫惰性求值
        stream.forEach(System.out::println);
    }

    /**
     * limit :截断流，使其元素不超过给定数
     */
    @Test
    public void test2() {
        appleList.stream()
                .filter(apple -> {
                    System.out.println("短路");
                    return apple.getWeight() > 156;
                })
                .limit(2)
                .forEach(System.out::println);
    }

    /**
     * skip:跳过n和元素，如果不足n个，则返回空流
     */
    @Test
    public void test3() {
        appleList.stream()
                .filter(apple -> apple.getWeight() > 150)
                .skip(2)
                .forEach(System.out::println);
    }

    /**
     * distinct:去重
     */
    @Test
    public void test4() {
        appleList.stream()
                .filter(apple -> apple.getWeight() > 150)
                .map(Apple::getColor)
                .distinct()
                .forEach(System.out::println);
    }

    /**
     * map:映射 将lambda表达式应用于每个元素上
     */
    @Test
    public void test5() {
        List<String> stringList = Arrays.asList("aaa", "bbbb", "ccc", "ddddd");
        stringList.stream()
                .map(s -> s.toUpperCase())
                .forEach(System.out::println);

        Stream<Stream<Character>> stream = stringList.stream()
                //{{a,a,a}{b,b,b}{c,c,c}}
                .map(TestStream2::filterCharacter);

        stream.forEach(sm -> {
            sm.forEach(System.out::print);
        });

        //flatMap--接收一个参数，将流中的每个值换成另一个流，然后把所有流连接成一个流
        stringList.stream()
                //{a,a,a,b,b,b,c,c,c}
                .flatMap(TestStream2::filterCharacter)
                .forEach(System.out::println);

        //mapToInt,mapToDouble,mapToLong如果是进行统计的这种用着三个方法
        //别将流中的元素特化为 int 、 long 和 double ，从而避免了暗含的装箱成本
        IntSummaryStatistics intSummaryStatistics = appleList.stream()
                .mapToInt(Apple::getWeight)
                .summaryStatistics();
        System.out.println("苹果平均重量：" + intSummaryStatistics.getAverage());
        System.out.println("苹果总个数：" + intSummaryStatistics.getCount());
        System.out.println("苹果最大重量：" + intSummaryStatistics.getMax());
        System.out.println("苹果最小重量：" + intSummaryStatistics.getMin());
        System.out.println("苹果总量总和：" + intSummaryStatistics.getSum());


        OptionalInt max = appleList.stream()
                .mapToInt(Apple::getWeight)
                .max();

        int i = appleList.stream()
                .mapToInt(Apple::getWeight)
                .max().orElse(1);

    }

    public static Stream<Character> filterCharacter(String str) {
        List<Character> list = new ArrayList<>();
        for (Character ch : str.toCharArray()) {
            list.add(ch);
        }
        return list.stream();
    }

    /**
     * sorted() 自然排序
     * sorted(Comparator com) --定制排序
     */
    @Test
    public void test6() {
        appleList.stream()
                .map(Apple::getWeight)
                .sorted()
                .forEach(System.out::println);
        System.out.println("---------------");
        appleList.stream()
                .sorted((e1, e2) -> {
                    if (e1.getWeight().equals(e2.getWeight())) {
                        return e1.getColor().compareTo(e2.getColor());
                    }
                    return e1.getWeight().compareTo(e2.getWeight());
                }).forEach(System.out::println);
        System.out.println("---------------");
        appleList.stream()
                .sorted(comparing(Apple::getWeight)).forEach(System.out::println);
    }

    @Test
    public void test7() {
        int sum = appleList.stream().filter(distinctByKey(Apple::getWeight)).mapToInt(Apple::getWeight).sum();
        System.out.println(sum);
    }

    static <T> Predicate<T> distinctByKey(Function<? super T, ?> keyExtractor) {
        Map<Object, Boolean> seen = new ConcurrentHashMap<>(0);
        return t -> seen.putIfAbsent(keyExtractor.apply(t), Boolean.TRUE) == null;
    }

    @Test
    public void test8() {
        List<String> stringList = Arrays.asList("aa", "bb", "cc", "dd", "ee");
        Collections.shuffle(stringList);
        //        while (true){
//            if(CollectionUtils.isEmpty(stringList)){
//                break;
//            }
        System.out.println(stringList.stream().limit(2).collect(Collectors.toList()));
//            stringList = stringList.stream().skip(2).collect(Collectors.toList());
//
//        }

    }
}
